/*
 * Copyright 2010 Cedric Priscal
 *
 * This file is part of stupid-avr-robot.
 *
 * stupid-avr-robot is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * stupid-avr-robot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with stupid-avr-robot.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef ANALOGCHANNEL_H_
#define ANALOGCHANNEL_H_

#include <avr/io.h>
#include "Timer/Timer.h"

/**
 * @brief Enumeration of the available analog channels.
 * @see AnalogChannel
 */
typedef enum {
	CHANNEL_ADC0=0,
	CHANNEL_ADC1=1,
	CHANNEL_ADC2=2,
	CHANNEL_ADC3=3,
	CHANNEL_ADC4=4,
	CHANNEL_ADC5=5,
	CHANNEL_ADC6=6,
	CHANNEL_ADC7=7,
	CHANNEL_ADC8=8,
	CHANNEL_VBG=14,
	CHANNEL_GND=15
} CHANNEL;

/**
 * @brief Enumeration of the available voltage references.
 * @see AnalogChannel
 */
typedef enum {
	VREF_AVCC = _BV(REFS0),           //!< VREF_AVCC
	VREF_VBG = _BV(REFS1) | _BV(REFS0)//!< VREF_VBG
} VREF;

/**
 * @brief Base class for one channel of the AVR internal ADC.
 *
 * In order to use this class, you have to inherit this
 * abstract class with your own, and override the method @a
 * onNewMeasure() to get the ADC measures.
 */
class AnalogChannel : private TimerListener {

private:
	unsigned short mPeriod;
	unsigned short mMs;
	void onTimer(char what, unsigned short when);

public:
	CHANNEL mChannel;
	VREF mVref;

	/**
	 * @brief Constructor.
	 * @param channel
	 * @param vref
	 */
	AnalogChannel(CHANNEL channel, VREF vref);

	/**
	 * @brief Trigger a single ADC conversion.
	 *
	 * This method is non-blocking, @a onNewMeasure() will
	 * be called when a the result is available.
	 */
	void startOneShot();

	/**
	 * @brief Trigger periodic ADC conversions.
	 *
	 * This method is non-blocking, @a onNewMeasure() will
	 * be called each time a the result is available.
	 *
	 * @param period Refresh period in milliseconds.
	 */
	void startPeriodic(unsigned short period);

	/**
	 * @brief Stops any ADC background operation.
	 */
	void stop();

	/**
	 * @brief Method to override in order to get the ADC results.
	 * @param value Result of the ADC conversion.
	 */
	virtual void onNewMeasure(unsigned short value) = 0;
};

#endif /* ANALOGCHANNEL_H_ */
